import os
import uuid
from fastapi import FastAPI,HTTPException,File, UploadFile
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from knowledge_base import KnowledgeBase
from shop_table import ShopTable
from dashscope_api import DashscopeApi 
from prompt import generate_prompt
from typing import List, Tuple
import jieba
import shutil


app = FastAPI()

# 添加CORS中间件配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有源，生产环境中应该设置具体的源
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法
    allow_headers=["*"],  # 允许所有头
)

# 在 app 初始化后添加
app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads")

class QuestionRequest(BaseModel):
    question: str

class QuestionListRequest(BaseModel):
    question: str

class KnowledgeItem(BaseModel):
    question: str
    answer: str

class QuestionResponse(BaseModel):
    user_question: str
    related_knowledge: str
    generated_answer: str

class QuestionListResponse(BaseModel):
    list: List[KnowledgeItem] 

class ImageUploadResponse(BaseModel):
    filename: str
    file_path: str

class ImageItem(BaseModel):
    filename: str
    url: str

class ImageListResponse(BaseModel):
    images: List[ImageItem]

class DeleteImageRequest(BaseModel):
    filename: str  # 需要删除的图片文件名

class DeleteImageResponse(BaseModel):
    success: bool
    message: str

def initialize_database():
    # 初始化知识库示例数据
    kb = KnowledgeBase()
    
    # kb.insert("退款？", "您可以在APP内【我的订单】中选择需要退款的订单，点击【申请退款】并填写原因，我们将在24小时内审核。")
    # kb.insert("产品保修期多久？", "我们的产品提供1年免费保修服务，从购买日期开始计算。")
    # kb.insert("休息天周末安排", "早上7点半起床及晨间准备，8点去吃早餐，10点半去游泳，下午1点打游戏，3点半点后打扫家睡觉")
    # kb.insert("")
    kb.close()
    # 初始化商店表格数据
    # st = ShopTable()
    # st.insert("牛奶", "750ml", "10元","1号货柜3层")
    # st.insert("饼干", "250g", "4元","3号货柜3层")
    # st.insert("电视", "24英寸", "1080元","15号货柜1层")
    # st.close()


def preprocess_question(question: str) -> str:
    # 1. 去除标点符号和特殊字符
    import re
    question = re.sub(r'[^\w\s]', '', question)
    # 2. 分词（可以使用jieba等中文分词库）
    words = jieba.cut(question)
    # 3. 去除停用词
    stopwords = {'的', '了', '和', '是', '在', '我', '有', '个', '想', '要', '问', '吗', '怎么', '如何', '什么'}
    words = [w for w in words if w not in stopwords and len(w.strip()) > 0]
    # 4. 返回分词结果
    return question,' '.join(words)
# 计算相似度并过滤结果
def calculate_similarity(text1: str, text2: str) -> float:
    # 对两个文本都进行预处理
    _,words1 = preprocess_question(text1)
    _,words2 = preprocess_question(text2)
    # 转换为集合
    set1 = set(words1)
    set2 = set(words2)
    # 计算 Jaccard 相似度
    intersection = set1 & set2
    union = set1 | set2
    return len(intersection) / len(union) if union else 0
def answer_question(user_question: str, api_key: str) -> QuestionResponse:
    # 预处理用户问题
    original_question, processed_question = preprocess_question(user_question)
    kb = KnowledgeBase()
    st = ShopTable()
    print(processed_question,"processed_question")
     # 使用处理后的问题进行搜索
    kb_knowledge = kb.search(processed_question)
    st_results = st.search(processed_question)

    # 过滤知识库结果
    filtered_kb = [
        (q, a) for q, a in kb_knowledge 
        if calculate_similarity(q, user_question) > 0.3  # 设置相似度阈值
    ]
    
    # 转换并过滤商品信息
    st_knowledge = [
        (item[0], f"规格：{item[1]}，价格：{item[2]}，位置：{item[3]}") 
        for item in st_results
        if calculate_similarity(item[0], user_question) > 0.3  # 设置相似度阈值
    ]
    
    # 合并过滤后的结果
    related_knowledge = filtered_kb + st_knowledge
     # 如果没有找到相关结果，尝试模糊匹配
    print(f"模糊匹配结果：{related_knowledge}")

    if not related_knowledge:
        # 降低相似度阈值重新搜索
        filtered_kb = [
            (q, a) for q, a in kb_knowledge 
            if calculate_similarity(q, user_question) > 0.1
        ]
        st_knowledge = [
            (item[0], f"规格：{item[1]}，价格：{item[2]}，位置：{item[3]}") 
            for item in st_results
            if calculate_similarity(item[0], user_question) > 0.1
        ]
        related_knowledge = filtered_kb + st_knowledge
        print(f"模糊匹配结果：{related_knowledge}")
    kb.close()
    st.close()
    
   # 构建上下文
    if related_knowledge:
        context = "\n\n".join([f"Q: {q}\nA: {a}" for q, a in related_knowledge])
    else:
        context = "未找到相关信息"
    prompt = generate_prompt(user_question, context)
    
    client = DashscopeApi(api_key)
    generated_answer = client.get_answer(prompt)
    
    return QuestionResponse(
        user_question=f"用户问题：{user_question}",
         related_knowledge=f"知识库参考：{related_knowledge if related_knowledge else '未找到相关信息'}",
        generated_answer=f"Ai生成答案：{generated_answer}"
    )

@app.post("/api/questionList", response_model=QuestionListResponse)
async def handle_question(request: QuestionListRequest):
    kb = KnowledgeBase()
    kb_knowledge = kb.search(request.question)
    kb_knowledgeList = [
        KnowledgeItem(question=q, answer=a)
        for q, a in kb_knowledge
    ]
    kb.close()
    return QuestionListResponse(list=kb_knowledgeList)

@app.post("/api/question", response_model=QuestionResponse)
async def handle_question(request: QuestionRequest):
    api_key = os.getenv("DASHSCOPE_API_KEY")
    if not api_key:
        raise HTTPException(status_code=500, detail="API key not found")
    
    return answer_question(request.question, api_key)

@app.post("/api/uploadImage", response_model=ImageUploadResponse)
async def upload_image(
    file: UploadFile = File(..., description="上传的图片文件，支持格式: jpg, png, jpeg"),
):
    # 创建上传目录
    upload_dir = "uploads/images"
    os.makedirs(upload_dir, exist_ok=True)
    
    # 验证文件类型
    if not file.content_type.startswith('image/'):
        raise HTTPException(status_code=400, detail="仅支持图片文件上传")
    
    # 生成唯一文件名
    file_ext = os.path.splitext(file.filename)[1]
    safe_filename = f"{uuid.uuid4().hex}{file_ext}"
    
    # 保存文件
    save_path = os.path.join(upload_dir, safe_filename)
    with open(save_path, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    
    return ImageUploadResponse(
        filename=f"/{save_path.replace('\\', '/')}",
        file_path=f"/{save_path.replace('\\', '/')}"  # 统一路径格式
    )

@app.get("/api/listImages", response_model=ImageListResponse)
async def list_images():
    upload_dir = "uploads/images"
    images = []
    
    # 检查目录是否存在
    if os.path.exists(upload_dir):
        # 遍历目录获取图片文件
        for filename in os.listdir(upload_dir):
            if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
                images.append(ImageItem(
                    filename=filename,
                    url=f"/{upload_dir}/{filename}".replace('\\', '/')
                ))
    
    return ImageListResponse(images=images)

@app.delete("/api/deleteImage", response_model=DeleteImageResponse)
async def delete_image(request: DeleteImageRequest):
    upload_dir = "uploads/images"
    file_path = os.path.join(upload_dir, request.filename)
    
    # 检查文件是否存在
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="文件不存在")
    
    try:
        # 删除文件
        os.remove(file_path)
        return DeleteImageResponse(
            success=True,
            message=f"文件 {request.filename} 删除成功"
        )
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"删除失败: {str(e)}"
        )
    
if __name__ == "__main__":
    # 初始化数据库（首次运行时）
    # initialize_database()
    
    # 启动FastAPI服务
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
    
 